package com.zhiche.wms.service.stock.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.zhiche.wms.core.supports.BaseException;
import com.zhiche.wms.core.supports.enums.TableStatusEnum;
import com.zhiche.wms.core.utils.SnowFlakeId;
import com.zhiche.wms.domain.mapper.stock.StockMapper;
import com.zhiche.wms.domain.model.inbound.InboundPutawayLine;
import com.zhiche.wms.domain.model.movement.MovementHeader;
import com.zhiche.wms.domain.model.movement.MovementLine;
import com.zhiche.wms.domain.model.otm.OtmOrderRelease;
import com.zhiche.wms.domain.model.outbound.OutboundNoticeLine;
import com.zhiche.wms.domain.model.stock.Stock;
import com.zhiche.wms.domain.model.stock.StockDetail;
import com.zhiche.wms.domain.model.stock.StockProperty;
import com.zhiche.wms.domain.model.stockinit.StockInitLine;
import com.zhiche.wms.domain.model.sys.User;
import com.zhiche.wms.dto.outbound.StockSkuToPrepareDTO;
import com.zhiche.wms.dto.outbound.StockSkuToPrepareParamDTO;
import com.zhiche.wms.dto.stock.StockDTO;
import com.zhiche.wms.dto.stock.StockWithSkuDTO;
import com.zhiche.wms.service.base.IBusinessDocNumberService;
import com.zhiche.wms.service.base.IStoreLocationService;
import com.zhiche.wms.service.inbound.IInboundPutawayLineService;
import com.zhiche.wms.service.movement.IMovementHeaderService;
import com.zhiche.wms.service.opbaas.IOrderReleaseService;
import com.zhiche.wms.service.stock.IStockService;
import com.zhiche.wms.service.stockinit.IStockInitLineService;
import com.zhiche.wms.service.sys.IUserService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 库存 服务实现类
 * </p>
 *
 * @author zhaoguixin
 * @since 2018-05-30
 */
@Service
public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements IStockService {

    @Autowired
    private SkuServiceImpl skuService;
    @Autowired
    private SnowFlakeId snowFlakeId;
    @Autowired
    private StockDetailServiceImpl stockDetailService;
    @Autowired
    private IBusinessDocNumberService numberService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IMovementHeaderService movementHeaderService;
    @Autowired
    private IOrderReleaseService orderReleaseService;
    @Autowired
    private IInboundPutawayLineService putawayLineService;
    @Autowired
    private IStoreLocationService locationService;
    @Autowired
    private IStockInitLineService initLineService;


    @Override
    public Stock getUniqueStock(StockProperty stockProperty) {
        Long skuId = skuService.getUniqueSku(stockProperty).getId();

        EntityWrapper<Stock> ew = new EntityWrapper<>();
        ew.eq("store_house_id", stockProperty.getStoreHouseId());
        ew.eq("location_id", stockProperty.getLocationId());
        ew.eq("sku_id", skuId);
        Stock stock = selectOne(ew);

        if (Objects.equals(null, stock)) {
            stock = new Stock();
            stock.setStoreHouseId(stockProperty.getStoreHouseId());
            stock.setLocationId(stockProperty.getLocationId());
            stock.setSkuId(skuId);
            stock.setId(snowFlakeId.nextId());
            stock.setQty(BigDecimal.ZERO);
            stock.setNetWeight(BigDecimal.ZERO);
            stock.setGrossWeight(BigDecimal.ZERO);
            stock.setGrossCubage(BigDecimal.ZERO);
            stock.setPackedCount(BigDecimal.ZERO);

            boolean result = insert(stock);
            if (result) {
                return stock;
            } else {
                throw new BaseException(2000, "保存库存失败");
            }
        } else {
            return stock;
        }
    }

    @Override
//    @Transactional
    public Stock addStock(StockProperty stockProperty, String businessType, Long relationLineId) {
        return updateStockQty(stockProperty, "10", businessType, relationLineId);
    }

    @Override
    @Transactional
    public Stock minusStock(StockProperty stockProperty, String businessType, Long relationLineId) {
        if (Objects.equals(null, stockProperty.getQty())) throw new BaseException(2040, "数量不能为空！");
        stockProperty.setQty(BigDecimal.ZERO.subtract(stockProperty.getQty()));

        if (!Objects.equals(null, stockProperty.getNetWeight()))
            stockProperty.setNetWeight(BigDecimal.ZERO.subtract(stockProperty.getNetWeight()));
        if (!Objects.equals(null, stockProperty.getGrossWeight()))
            stockProperty.setGrossWeight(BigDecimal.ZERO.subtract(stockProperty.getGrossWeight()));
        if (!Objects.equals(null, stockProperty.getGrossCubage()))
            stockProperty.setGrossCubage(BigDecimal.ZERO.subtract(stockProperty.getGrossCubage()));
        if (!Objects.equals(null, stockProperty.getPackedCount()))
            stockProperty.setPackedCount(BigDecimal.ZERO.subtract(stockProperty.getPackedCount()));
        return updateStockQty(stockProperty, "20", businessType, relationLineId);
    }

    @Override
    public List<Stock> queryStockList(StockProperty stockProperty) {
        return baseMapper.queryStockList(stockProperty);
    }

    @Override
    public Page<StockDTO> queryPageStock(Page<StockDTO> page) {
        Wrapper<StockDTO> ew = buildCondition(page.getCondition());
        List<StockDTO> stockDTOList = baseMapper.selectPageStockDTO(page, ew);
        page.setRecords(stockDTOList);
        return page;
    }

    @Override
    public Page<StockDTO> queryPageStockByQrCode(Page<StockDTO> page) {
        if (!page.getCondition().containsKey("key") || Objects.isNull(page.getCondition().get("key"))) {
            throw new BaseException(2000, "扫描内容为空！");
        }
        String vin = getVinFromOR(page.getCondition().get("key").toString());
        page.getCondition().put("lotNo1", vin);
        Wrapper<StockDTO> ew = buildCondition(page.getCondition());
        List<StockDTO> stockDTOList = baseMapper.selectPageStockDTOByQrCode(page, ew);
        page.setRecords(stockDTOList);
        return page;
    }

    private String getVinFromOR(String key) {
        Wrapper<OtmOrderRelease> orEw = new EntityWrapper<>();
        orEw.eq("qr_code", key)
                .ne("status", TableStatusEnum.STATUS_50.getCode())
                .orderBy("id", false);
        List<OtmOrderRelease> orderReleases = orderReleaseService.selectList(orEw);
        if (Objects.nonNull(orderReleases) && orderReleases.size() > 0) {
            return orderReleases.get(0).getVin();
        } else {
            return key;
        }
    }

    @Override
    public List<StockDTO> exportStockData(Map<String, String> condition) {
        if (condition == null || condition.isEmpty()) {
            throw new BaseException("参数不能为空");
        }
        EntityWrapper<StockDTO> ew = new EntityWrapper<>();
        if (StringUtils.isBlank(condition.get("storeHouseId"))) {
            throw new BaseException("仓库信息不能为空");
        }
        ew.eq("store_house_id", condition.get("storeHouseId"));

        if (StringUtils.isNotBlank(condition.get("stockId"))) {
            ew.eq("stock_id", condition.get("stockId"));
        }
        if (StringUtils.isNotBlank(condition.get("lotNo1"))) {
            ew.like("lot_no1", condition.get("lotNo1"));
        }
        if (StringUtils.isNotBlank(condition.get("stockStatus"))) {
            ew.eq("stock_status", condition.get("stockStatus"));
        }
        if (StringUtils.isNotBlank(condition.get("ownerId"))) {
            ew.eq("owner_id", condition.get("ownerId"));
        }
        if (StringUtils.isNotBlank(condition.get("materielId"))) {
            ew.eq("materiel_id", condition.get("materielId"));
        }
        if (StringUtils.isNotBlank(condition.get("locationCode"))) {
            ew.eq("location_code", condition.get("locationCode"));
        }
        ew.orderBy("stock_id", false);
        return baseMapper.selectExportStockData(ew);
    }


    private Wrapper<StockDTO> buildCondition(Map<String, Object> condition) {
        Wrapper<StockDTO> ew = new EntityWrapper<>();
        if (!Objects.isNull(condition) && !condition.isEmpty()) {
            if (condition.containsKey("stockId") && Objects.nonNull(condition.get("stockId"))) {
                ew.eq("stock_id", condition.get("stockId").toString());
            }
            if (condition.containsKey("lotNo1") && Objects.nonNull(condition.get("lotNo1"))) {
                String[] split = condition.get("lotNo1").toString().split(",");
                List<String> vins = Arrays.asList(split);
                ew.in("lot_no1", vins).orNew().like("lot_no1", condition.get("lotNo1").toString());
            }
            if (condition.containsKey("stockStatus") && Objects.nonNull(condition.get("stockStatus"))) {
                ew.eq("stock_status", condition.get("stockStatus").toString());
            }
            if (condition.containsKey("ownerId") && Objects.nonNull(condition.get("ownerId"))) {
                ew.eq("owner_id", condition.get("ownerId").toString());
            }
            if (condition.containsKey("materielId") && Objects.nonNull(condition.get("materielId"))) {
                ew.eq("materiel_id", condition.get("materielId").toString());
            }
            if (condition.containsKey("storeHouseId") && Objects.nonNull(condition.get("storeHouseId"))) {
                ew.eq("store_house_id", condition.get("storeHouseId").toString());
            }
            if (!Objects.isNull(condition.get("locationCode")) && StringUtils.isNotBlank(condition.get("locationCode").toString().trim())) {
                ew.eq("location_code", condition.get("locationCode").toString());
            }
        }
        ew.orderBy("stock_id", false);
        return ew;
    }

    /**
     * 查询可用库存列表信息
     */
    @Override
    public List<StockSkuToPrepareDTO> selectStockToPrepareByParams(OutboundNoticeLine v, Long storeHouseId) {
        StockSkuToPrepareParamDTO paramDTO = new StockSkuToPrepareParamDTO();
        BeanUtils.copyProperties(v, paramDTO);
        paramDTO.setStoreHouseId(storeHouseId);
        return this.baseMapper.selectStockToPrepareByParams(paramDTO);
    }

    @Override
    public void lockStockBatch(List<Long> stockIds) {

        List<String> msgs = new ArrayList<>();
        for (Long stockId : stockIds) {
            String msg = "";
            Stock stock = this.selectById(stockId);
            if ("20".equals(stock.getStatus())) {
                msg = "库存:" + stock.getId() + ":已被锁定";
                msgs.add(msg);
                continue;
            }
            baseMapper.updateStockStatus(stockId, "20");
        }
    }

    @Override
    public void unlockStockBatch(List<Long> stockIds) {
        List<String> msgs = new ArrayList<>();
        for (Long stockId : stockIds) {
            String msg = "";
            Stock stock = this.selectById(stockId);
            if ("10".equals(stock.getStatus())) {
                msg = "库存:" + stock.getId() + ":已为正常";
                msgs.add(msg);
                continue;
            }
            baseMapper.updateStockStatus(stockId, "10");
        }
    }

    /**
     * 更新库位
     */
    @Override
    public void updateStockLocation(Map<String, String> condition) {
        if (Objects.isNull(condition) || condition.isEmpty()) {
            throw new BaseException("参数不能为空");
        }
        User loginUser = userService.getLoginUser();
        if (Objects.isNull(loginUser)) {
            throw new BaseException("请登陆后进行该操作");
        }
        String stockId = condition.get("stockId");
        String houseId = condition.get("houseId");
        String newLocationId = condition.get("newLocationId");
        if (StringUtils.isBlank(stockId)) {
            throw new BaseException("请选择要调整库位的数据");
        }
        if (StringUtils.isBlank(houseId)) {
            throw new BaseException("仓库信息不能为空");
        }
        if (StringUtils.isBlank(newLocationId)) {
            throw new BaseException("请选择调整的库位");
        }
        HashMap<String, Object> params = Maps.newHashMap();
        params.put("stockId", stockId);
        params.put("houseId", houseId);
        List<StockWithSkuDTO> list = selectStockWithSkuByParam(params);
        if (CollectionUtils.isEmpty(list)) {
            throw new BaseException("未查询到对应stockId:" + stockId + "的库存信息");
        }
        if (list.size() > 1) {
            throw new BaseException("查询到stockId:" + stockId + "的多条库存");
        }
        StockWithSkuDTO stockDTO = list.get(0);
//        StoreLocation storeLocation = locationService.selectLocationByLocationId(Long.valueOf(newLocationId));
        //调整入库记录库位信息
        EntityWrapper<InboundPutawayLine> ew = new EntityWrapper<>();
        ew.eq("lot_no1", stockDTO.getLotNo1())
                .eq("materiel_id", stockDTO.getMaterielId())
                .eq("owner_id", stockDTO.getOwnerId());
        ew.orderBy("gmt_create", false)
                .orderBy("id", false);
        List<InboundPutawayLine> lineList = putawayLineService.selectList(ew);
        HashMap<String, String> propCache = Maps.newHashMap();
        if (CollectionUtils.isEmpty(lineList)) {
            //车辆入库是通过期初库存导入
            EntityWrapper<StockInitLine> initEw = new EntityWrapper<>();
            ew.eq("lot_no1", stockDTO.getLotNo1())
                    .eq("materiel_id", stockDTO.getMaterielId())
                    .eq("owner_id", stockDTO.getOwnerId());
            ew.orderBy("gmt_create", false)
                    .orderBy("id", false);
            List<StockInitLine> stockInitLines = initLineService.selectList(initEw);
            if (CollectionUtils.isEmpty(stockInitLines)) {
                throw new BaseException("未查询到车架号:" + stockDTO.getLotNo1() + "入库/期初库存信息");
            }
            StockInitLine initLine = stockInitLines.get(0);
            propCache.put("materielName", initLine.getMaterielName());
            propCache.put("relationId", String.valueOf(initLine.getId()));
        } else {
            InboundPutawayLine putawayLine = lineList.get(0);
            propCache.put("materielName", putawayLine.getMaterielName());
            propCache.put("relationId", String.valueOf(putawayLine.getId()));
        }
        MovementHeader mh = buildMovement(loginUser,
                houseId,
                newLocationId,
                stockDTO, propCache);
        boolean isUpdate = movementHeaderService.createAndAuditMovenment(mh);
        if (!isUpdate) {
            throw new BaseException("库位调整失败");
        }


    }

    private MovementHeader buildMovement(User loginUser,
                                         String houseId,
                                         String newLocationId,
                                         StockWithSkuDTO stockDTO,
                                         HashMap<String, String> propCache) {
        MovementHeader mh = new MovementHeader();
        mh.setId(snowFlakeId.nextId());
        mh.setMovementNo(numberService.getMovementNo());
        mh.setStoreHouseId(Long.valueOf(houseId));
        mh.setOwnerId(stockDTO.getOwnerId());
        mh.setOrderDate(new Date());
        mh.setBusinessType(TableStatusEnum.STATUS_30.getCode());
        mh.setBusinessDocId(0L);
        mh.setLineCount(0);
        mh.setStatus(TableStatusEnum.STATUS_10.getCode());
        mh.setUserCreate(loginUser.getName());
        mh.setUserModified(loginUser.getName());
        mh.setGmtCreate(null);
        mh.setGmtModified(null);

        MovementLine ml = new MovementLine();
        ml.setId(snowFlakeId.nextId());
        ml.setHeaderId(mh.getId());
        ml.setType(TableStatusEnum.STATUS_30.getCode());
        ml.setOwnerId(stockDTO.getOwnerId());
        ml.setMaterielId(stockDTO.getMaterielId());
        ml.setRelationLineId(propCache.get("relationId") == null ? null : Long.valueOf(propCache.get("relationId")));
        //ml.setMaterielCode("");
        ml.setMaterielName(StringUtils.isBlank(propCache.get("materielName")) ? null : propCache.get("materielName"));
        ml.setSourceLocationId(stockDTO.getLocationId());
        ml.setDestinationLocationId(Long.valueOf(newLocationId));
        ml.setUom(stockDTO.getUom());
        ml.setQty(stockDTO.getQty());
        ml.setNetWeight(stockDTO.getNetWeight());
        ml.setGrossWeight(stockDTO.getGrossWeight());
        ml.setGrossCubage(stockDTO.getGrossCubage());
        ml.setPackedCount(stockDTO.getPackedCount());
        ml.setLotNo0(stockDTO.getLotNo0());
        ml.setLotNo1(stockDTO.getLotNo1());
        ml.setLotNo2(stockDTO.getLotNo2());
        ml.setLotNo3(stockDTO.getLotNo3());
        ml.setLotNo4(stockDTO.getLotNo4());
        ml.setLotNo5(stockDTO.getLotNo5());
        ml.setLotNo6(stockDTO.getLotNo6());
        ml.setLotNo7(stockDTO.getLotNo7());
        ml.setLotNo8(stockDTO.getLotNo8());
        ml.setLotNo9(stockDTO.getLotNo9());
        ml.setRemarks("库存页面库位调整");
        ml.setGmtCreate(null);
        ml.setGmtModified(null);
        ArrayList<MovementLine> mls = Lists.newArrayList();
        mls.add(ml);
        mh.setMovementLineList(mls);
        return mh;
    }

    @Override
    public List<StockWithSkuDTO> selectStockWithSkuByParam(HashMap<String, Object> params) {
        return this.baseMapper.selectStockWithSkuByParam(params);
    }

    /**
     * 插入明细账
     */
    public Stock updateStockQty(StockProperty stockProperty, String type, String businessType, Long relationLineId) {

        //库存
        Stock stock = getUniqueStock(stockProperty);
        stockProperty.setStockId(stock.getId());

        //库存明细账
        StockDetail stockDetail = new StockDetail();
        stockDetail.setId(snowFlakeId.nextId());
        stockDetail.setStockId(stockProperty.getStockId());
        stockDetail.setType(type);
        stockDetail.setBusinessType(businessType);
        stockDetail.setRelationLineId(relationLineId);
        stockDetail.setQty(stockProperty.getQty());
        stockDetail.setNetWeight(stockProperty.getNetWeight());
        stockDetail.setGrossWeight(stockProperty.getGrossWeight());
        stockDetail.setGrossCubage(stockProperty.getGrossCubage());
        stockDetail.setPackedCount(stockProperty.getPackedCount());

        try {
            boolean resultDetail = stockDetailService.insert(stockDetail);
            Integer result = baseMapper.updateStockQtyById(stockProperty);

            if (!resultDetail) throw new BaseException(2020, "保存库存明细失败！");
            if (result < 1) throw new BaseException(2010, "更新库存失败");

            return selectById(stockProperty.getStockId());
        } catch (Exception e) {
            throw e;
        }
    }

}
